package cn.getech.data.metadata.controller.blood;

import cn.getech.data.intelligence.common.exception.RRException;
import cn.getech.data.intelligence.common.validator.ValidatorUtils;
import cn.getech.data.metadata.model.excel.CollectionBloodExcel;
import cn.getech.data.metadata.model.excel.CollectionBloodExcelError;
import cn.getech.data.metadata.model.excel.ExcelError;
import cn.getech.data.metadata.service.CollectionBloodService;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class BloodTableFieldListener extends AnalysisEventListener<CollectionBloodExcel> {

    private List<CollectionBloodExcel> list = new ArrayList<>();
    private CollectionBloodService collectionBloodService;
    private Boolean check = false;
    private JSONObject data;
    private List<ExcelError> errorList = Lists.newArrayList();
    private Long userId;
    private Integer tenantId;
    private static Map<Long, List<CollectionBloodExcelError>> mapError = Maps.newHashMap();

    public static List<CollectionBloodExcelError> getFailList(Long userId) {
        return mapError.get(userId);
    }

    public BloodTableFieldListener(CollectionBloodService collectionBloodService, JSONObject res, boolean check) {
        this.collectionBloodService = collectionBloodService;
        this.check = check;
        this.data = res;
    }

    public BloodTableFieldListener(CollectionBloodService collectionBloodService, JSONObject res, Long userId, Integer tenantId) {
        this.data = res;
        this.collectionBloodService = collectionBloodService;
        this.userId = userId;
        this.tenantId=tenantId;
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        Field[] fields = CollectionBloodExcel.class.getDeclaredFields();
        for (Integer integer : headMap.keySet()) {
            Field field = fields[integer];
            ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
            if (excelProperty != null) {
                if (!excelProperty.value()[0].equals(headMap.get(integer).trim())) {
                    throw new RRException("excel模板内容格式错误");
                }
            }
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws RRException {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException e = (ExcelDataConvertException) exception;
            ExcelError errorDTO = new ExcelError();
            errorDTO.setHeadName(String.join(",", e.getExcelContentProperty().getHead().getHeadNameList()));
            errorDTO.setRowIndex(e.getRowIndex() + 1);
            errorDTO.setColumnIndex(e.getColumnIndex() + 1);
            errorDTO.setErrMsg("第" + errorDTO.getRowIndex() + " 行第" + errorDTO.getColumnIndex() + "列," + "数据类型错误");
            errorDTO.setValue(e.getCellData().getStringValue());
            errorList.add(errorDTO);
        } else if (exception instanceof RRException) {
            throw new RRException(((RRException) exception).getMsg());
        }
        exception.printStackTrace();
    }

    @Override
    public void invoke(CollectionBloodExcel data, AnalysisContext context) {
        if (check) {
            ReadRowHolder readRowHolder = context.readRowHolder();
            Integer rowIndex = readRowHolder.getRowIndex();
            ExcelError errorDTO = new ExcelError();
            errorDTO.setRowIndex(rowIndex + 1);
            try {
                ValidatorUtils.validateEntity(data);
                String errorField = data.validateValue();
                if (StringUtils.isNotEmpty(errorField)) {
                    errorDTO.setErrMsg("第" + errorDTO.getRowIndex() + "行," + errorField);
                    errorList.add(errorDTO);
                } else {
                    list.add(data);
                }
            } catch (RRException e) {
                errorDTO.setErrMsg("第" + errorDTO.getRowIndex() + "行," + e.getMsg());
                errorList.add(errorDTO);
            }
        } else {
            data.setOrder(list.size() + 1);
            list.add(data);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        Set<String> uni = Sets.newHashSet();
        for (CollectionBloodExcel collectionBloodExcel : list) {
            uni.add(collectionBloodExcel.getUniqueBlood());
        }
        if (uni.size() != list.size()) {
            data.put("error_log", "血缘关系中存在重复配置");
        }
        if (CollectionUtil.isNotEmpty(errorList)) {
            List<String> msg = errorList.stream()
                    .map(ExcelError::getErrMsg).collect(Collectors.toList());
            data.put("error_log", String.join("\n", msg));
        } else if (CollectionUtil.isEmpty(list)) {
            data.put("error_log", "文件内容为空");
        } else if (!check) {
            List<CollectionBloodExcelError> failList = new ArrayList<>(list.size());
            collectionBloodService.saveBatch(list, failList,tenantId);
            mapError.put(userId, failList);
            //缘关系导入结果：血缘关系共计100条，其中导入成功40条，导入失败60条。
            data.put("success", list.size() - failList.size());
            data.put("fail", failList.size());
            data.put("total", list.size());
        }
    }
}

